<template>
  <div class="container">
    <h1>图片压缩工具</h1>
    <div class="upload-area">
      <el-upload
        class="upload-component"
        drag
        action="#"
        :auto-upload="false"
        :show-file-list="false"
        accept="image/*"
        @change="handleFileChange"
        @drop.prevent="handleDrop"
        @dragover.prevent="handleDragOver"
        @dragleave.prevent="handleDragLeave">
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">
          拖拽图片到此处或 <em>点击上传</em>
        </div>
      </el-upload>
    </div>

    <div v-if="imageInfo" class="compression-panel">
      <div class="preview-container">
        <div class="preview-box">
          <h3>原始图片</h3>
          <img :src="originalPreview" alt="原始图片" />
          <p>大小: {{ formatFileSize(imageInfo.originalSize) }}</p>
        </div>
        <div class="preview-box">
          <h3>压缩预览</h3>
          <img v-if="compressedPreview" :src="compressedPreview" alt="压缩预览" />
          <p v-if="compressedSize">大小: {{ formatFileSize(compressedSize) }}</p>
        </div>
      </div>

      <div class="compression-controls">
        <el-form :model="compressionParams" label-width="120px">
          <el-form-item label="目标文件大小">
            <el-input-number
              v-model="compressionParams.targetSize"
              :min="1"
              :max="10000"
              :step="100"
              @change="handleCompress"
            /> KB
          </el-form-item>
          <el-form-item label="图片质量">
            <el-slider
              v-model="compressionParams.quality"
              :min="1"
              :max="100"
              @change="handleCompress"
            />
          </el-form-item>
        </el-form>

        <el-button type="primary" @click="downloadCompressed" :disabled="!compressedPreview">
          下载压缩图片
        </el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { UploadFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

const imageInfo = ref(null)
const originalPreview = ref('')
const compressedPreview = ref('')
const compressedSize = ref(0)

const compressionParams = reactive({
  targetSize: 500, // 默认目标大小500KB
  quality: 80 // 默认质量80%
})

const handleFileChange = (file) => {
  const fileObj = file.raw
  if (!fileObj) return

  // 检查文件类型
  if (!fileObj.type.startsWith('image/')) {
    ElMessage.error('请上传图片文件！')
    return
  }

  // 保存原始图片信息
  imageInfo.value = {
    file: fileObj,
    originalSize: fileObj.size
  }

  // 显示原始图片预览
  const reader = new FileReader()
  reader.onload = (e) => {
    originalPreview.value = e.target.result
    handleCompress() // 自动进行首次压缩
  }
  reader.readAsDataURL(fileObj)
}

const handleCompress = async () => {
  if (!imageInfo.value) return

  const img = new Image()
  img.src = originalPreview.value

  await new Promise((resolve) => {
    img.onload = resolve
  })

  const originalWidth = img.width
  const originalHeight = img.height
  const aspectRatio = originalWidth / originalHeight

  // 压缩图片函数
  const compressImage = async (width, height, quality) => {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    canvas.width = width
    canvas.height = height

    // 绘制图片
    ctx.drawImage(img, 0, 0, width, height)

    return new Promise((resolve) => {
      canvas.toBlob(
        (blob) => {
          const url = URL.createObjectURL(blob)
          compressedPreview.value = url
          compressedSize.value = blob.size
          resolve(blob)
        },
        'image/jpeg',
        quality / 100
      )
    })
  }

  const targetSize = compressionParams.targetSize * 1024 // 转换为字节
  let bestWidth = originalWidth
  let bestHeight = originalHeight
  let bestQuality = compressionParams.quality
  let bestSize = Infinity
  let bestBlob = null

  // 使用二分查找来寻找合适的质量参数
  const findBestQuality = async (width, height) => {
    let left = 1
    let right = 100
    let lastBlob = null

    while (left <= right) {
      const quality = Math.floor((left + right) / 2)
      const blob = await compressImage(width, height, quality)
      console.log(`尝试质量: ${quality}, 大小: ${formatFileSize(blob.size)}, 目标: ${formatFileSize(targetSize)}`)

      if (Math.abs(blob.size - targetSize) < Math.abs(bestSize - targetSize)) {
        bestQuality = quality
        bestSize = blob.size
        bestBlob = blob
        bestWidth = width
        bestHeight = height
      }

      if (blob.size > targetSize) {
        right = quality - 1
      } else {
        left = quality + 1
      }

      lastBlob = blob
    }

    return lastBlob
  }

  // 使用二分查找来寻找合适的尺寸
  let left = Math.min(100, originalWidth)
  let right = Math.min(1920, originalWidth)

  while (left <= right) {
    const width = Math.floor((left + right) / 2)
    const height = Math.round(width / aspectRatio)
    console.log(`尝试尺寸: ${width}x${height}`)

    const blob = await findBestQuality(width, height)

    if (blob.size > targetSize) {
      right = width - 1
    } else {
      left = width + 1
    }
  }

  // 使用最佳参数进行最终压缩
  if (bestBlob) {
    const url = URL.createObjectURL(bestBlob)
    compressedPreview.value = url
    compressedSize.value = bestBlob.size
    console.log(`压缩完成! 最终尺寸: ${bestWidth}x${bestHeight}, 质量: ${bestQuality}, 文件大小: ${formatFileSize(bestBlob.size)}`)
  }
}

const downloadCompressed = () => {
  if (!compressedPreview.value) return

  const link = document.createElement('a')
  link.download = `compressed_${imageInfo.value.file.name}`
  link.href = compressedPreview.value
  link.click()
}

const formatFileSize = (bytes) => {
  if (bytes < 1024) return bytes + ' B'
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB'
  return (bytes / (1024 * 1024)).toFixed(2) + ' MB'
}

const handleDrop = (e) => {
  // 由于在模板中已经使用了.prevent修饰符，这里不需要再次调用preventDefault
  // e.preventDefault()
  e.stopPropagation()
  console.log('Drop event triggered', e)
  
  const files = e.dataTransfer.files
  if (files && files.length > 0) {
    const file = files[0]
    console.log('Dropped file:', file.name, file.type)
    if (!file.type.startsWith('image/')) {
      ElMessage.error('请上传图片文件！')
      return
    }
    handleFileChange({ raw: file })
  } else {
    console.log('No files found in drop event')
  }
  
  // 确保获取到正确的拖拽区域元素
  const uploadDragger = document.querySelector('.el-upload-dragger')
  if (uploadDragger) {
    uploadDragger.classList.remove('is-dragover')
    uploadDragger.style.cursor = ''
  } else {
    console.log('Upload dragger element not found')
  }
}

const handleDragOver = (e) => {
  e.stopPropagation()
  
  const items = e.dataTransfer.items
  let isValid = false
  
  if (items && items.length > 0) {
    const item = items[0]
    isValid = item.kind === 'file' && item.type.startsWith('image/')
  }

  const uploadDragger = document.querySelector('.el-upload-dragger')
  if (uploadDragger) {
    if (isValid) {
      uploadDragger.classList.add('is-dragover')
      uploadDragger.style.cursor = 'copy'
    } else {
      uploadDragger.classList.remove('is-dragover')
      uploadDragger.style.cursor = 'no-drop'
    }
  }
}


const handleDragLeave = (e) => {
  // 由于在模板中已经使用了.prevent修饰符，这里不需要再次调用preventDefault
  // e.preventDefault()
  console.log('DragLeave event triggered')
  
  // 确保获取到正确的拖拽区域元素
  const uploadDragger = document.querySelector('.el-upload-dragger')
  if (uploadDragger) {
    uploadDragger.classList.remove('is-dragover')
    uploadDragger.style.cursor = ''
  } else {
    console.log('Upload dragger element not found in dragleave')
  }
}
</script>

<style scoped>
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

h1 {
  text-align: center;
  margin-bottom: 30px;
}

.upload-area {
  margin-bottom: 30px;
}

.upload-component {
  width: 100%;
}

.upload-component :deep(.el-upload) {
  width: 100%;
}

.upload-component :deep(.el-upload-dragger) {
  width: 100%;
  height: 200px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 2px dashed var(--el-border-color);
  border-radius: 8px;
  transition: all 0.3s;
}

.upload-component :deep(.el-upload-dragger:hover),
.upload-component :deep(.el-upload-dragger.is-dragover) {
  background-color: var(--el-color-primary-light-9);
  border-color: var(--el-color-primary);
}

.upload-component :deep(.el-icon--upload) {
  font-size: 48px;
  color: var(--el-color-primary);
  margin-bottom: 16px;
}

.upload-component :deep(.el-upload__text) {
  color: var(--el-text-color-regular);
  font-size: 16px;
}

.upload-component :deep(.el-upload__text em) {
  color: var(--el-color-primary);
  font-style: normal;
  font-weight: bold;
}
.compression-panel {
  background-color: #f5f7fa;
  padding: 20px;
  border-radius: 8px;
}

.preview-container {
  display: flex;
  justify-content: space-between;
  margin-bottom: 30px;
  gap: 20px;
}

.preview-box {
  flex: 1;
  text-align: center;
  background-color: white;
  padding: 15px;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  display: flex;
  flex-direction: column;
  height: 400px;
}

.preview-box img {
  flex: 1;
  width: 100%;
  height: auto;
  max-height: 320px;
  object-fit: contain;
  margin: 10px 0;
}

.preview-box h3 {
  margin: 0 0 10px 0;
}

.preview-box p {
  margin: 10px 0 0 0;
}

.compression-controls {
  max-width: 500px;
  margin: 0 auto;
}

.el-form-item {
  margin-bottom: 20px;
}
</style>